<?php

namespace App\Http\Controllers\Api\Token;

use App\Http\Controllers\ApiController;
use App\Project\Auth\Token\TokenRepository;
use App\Transformers\Api\TokenTransformer;
use Illuminate\Http\Request;

class TokenController extends ApiController
{
    /**
     * @var \Illuminate\Http\Request
     */
    protected $request;

    protected $token;

    public function __construct(Request $request)
    {
        parent::__construct();

        $this->request = $request;
        $this->token = new TokenRepository();
    }

    /**
     * 发放token
     * @return \Illuminate\Http\JsonResponse
     * @throws \Illuminate\Validation\ValidationException
     */
    public function issue()
    {
        $this->validateInput();

        $guard = 'api_' . $this->request->input('guard');

        return $this->attempt(
            $guard, $this->conditions(), $this->request->input('password')
        );
    }

    /**
     * 刷新token，携带原有token进行更换，由中间件控制必须携带token
     * @return \Illuminate\Http\JsonResponse
     * @throws \Illuminate\Validation\ValidationException
     */
    public function refresh()
    {
        return $this->issue();
    }

    protected function attempt($guard, array $condition, $password)
    {
        $provider = $this->getProvider($guard);

        if (!($user = $provider->retrieveByCredentials($condition))) {
            return $this->failedAuthenticate('未找到该账号。', 40101);
        }

        if (!$provider->validateCredentials($user, ['password' => $password])) {
            return $this->failedAuthenticate('密码错误。', 40102);
        }
        $type = true;

        switch ($guard) {
            case 'api_patient':
                if ($user->type == 1) {
                    $type = false;
                }
                break;
            case 'api_doctor':
                if ($user->type != 1) {
                    $type = false;
                }
                break;
        }

        if ($type) {
            return $this->failedAuthenticate('请确定身份后登陆相应客户端。', 40103);
        }

        $this->newToken($user);

        //如果登陆成功的话
        $user->LASTLOGIN = date('Y-m-d H:i:s',time());
        $user->save();

        return $this->successAuthenticate($user);
    }

    protected function newToken($user)
    {
        return $this->token->forUser($user)->refresh()
            ->then(function ($token, $user) {
                $user->api_token = $token;
                $user->save();
            })->getToken();
    }

    /**
     * @param $guard
     * @return \Illuminate\Contracts\Auth\UserProvider
     */
    protected function getProvider($guard)
    {
        $provider = config('auth.guards.' . $guard . '.provider');

        return \Auth::createUserProvider(config('auth.providers.' . $provider . '.driver'));
    }

    /**
     * @throws \Illuminate\Validation\ValidationException
     */
    protected function validateInput()
    {
        $this->validate($this->request, [
            'phone' => 'required|string',
            'password' => 'required|string',
            'guard' => 'required|in:patient,doctor',
        ]);
    }

    protected function conditions()
    {
        return ['phone' => $this->request->input('phone')];
    }

    protected function failedAuthenticate($message = '', $code)
    {
        $this->message = $message ?: 'Unauthenticated';
        $this->code = $code;

        return $this->hasNoData();
    }

    protected function successAuthenticate($user)
    {
        $this->message = '认证成功';
        $this->code = 10000;

        return $this->item($user, new TokenTransformer());
    }
}
